mod constants;
mod handlers;

use model_graph_common::utils::{read_bytes_from_pathbuf, rrg01_home_path};
use std::path::PathBuf;
use tauri::{
    http,
    plugin::{Builder, TauriPlugin},
    AppHandle, Manager, Runtime,
};

/// Initializes the plugin.
pub fn init<R: Runtime>() -> TauriPlugin<R> {
    Builder::new("mg-platform")
        .invoke_handler(tauri::generate_handler![
            handlers::file_download,
            handlers::file_unzip,
            handlers::file_compress_dir,
            handlers::file_compress_file,
            handlers::home_path,
            handlers::peer_id,
            handlers::peer_login,
            handlers::peer_status,
            handlers::peer_assistant_chat,
            handlers::peer_assistant_sv2tts,
            handlers::peer_assistant_shell,
            handlers::peer_assistant_batch_script,
            handlers::channel_pubsub_publish,
            handlers::channel_pubsub_publish_message,
            handlers::channel_pubsub_subscribe,
            handlers::channel_uicmd_response,
            handlers::channel_uicmd_remote_request,
            handlers::extractor_meta_from_database,
            handlers::workflow_execute,
            handlers::window::eval,
            handlers::window::window_set_url,
            handlers::container::datasource::ds_find_one_by_id,
            handlers::container::datasource::ds_find_one,
            handlers::container::datasource::ds_find,
            handlers::container::datasource::ds_count,
            handlers::container::datasource::ds_delete,
            handlers::container::datasource::ds_insert,
            handlers::container::datasource::ds_update_by_keys,
            handlers::container::datasource::ds_update,
            handlers::container::datasource::ds_batch_query,
            handlers::container::datasource::ds_batch_insert,
            handlers::container::datasource::ds_batch_update,
            handlers::container::datasource::ds_batch_delete,
            handlers::container::meta::meta_find_class,
            handlers::container::meta::meta_domain_classes,
            handlers::container::meta::meta_generate_sql,
            handlers::transform::transform_data,
            handlers::transform::transform_domain,
            handlers::transform::transform_domain_export,
            handlers::transform::transform_domain_import,
            handlers::transform::transform_domain_clear,
            handlers::transform::transform_domain_delete,
            handlers::builder::builder_gserver_config,
            handlers::prompt::prompt_generate_with_buildin,
            handlers::application::agent::app_agent_chat_send,
            handlers::application::agent::app_datasource,
            handlers::model::ollama::ollama_provider,
            handlers::model::ollama::ollama_list,
            handlers::model::ollama::ollama_pull,
            handlers::model::ollama::ollama_show,
            handlers::model::ollama::ollama_remove,
        ])
        .register_uri_scheme_protocol("rrg01", |_ctx, req| {
            let result = rrapp_protocol(req);
            match result {
                Ok(r) => r,
                Err(err) => {
                    tracing::error!("{}", err);
                    let body: Vec<u8> = vec![];
                    http::Response::builder().body(body).unwrap()
                }
            }
        })
        .setup(|app, api| {
            app.manage(handlers::ContextState::default());
            Ok(())
        })
        .build()
}

pub fn rrapp_protocol(request: http::Request<Vec<u8>>) -> anyhow::Result<http::Response<Vec<u8>>> {
    let url = request.uri().clone();
    let method = request.method().clone();
    let version = request.version().clone();
    let request_headers = request.headers().clone();
    // let body = request.body();

    let host_header_value: Vec<&str> = url
        .host()
        .ok_or(anyhow::anyhow!("获取host失败"))?
        .split(".")
        .collect();
    tracing::debug!("host:{:#?}", host_header_value);

    //[_identifier].localhost/
    //[project_application].localhost/
    let plugin_id = host_header_value
        .get(0)
        .map_or(Err(::anyhow::anyhow!("URL中无法找到peer_id")), |v| {
            Ok(String::from(*v))
        })?;
    let identifiers: Vec<&str> = plugin_id.split("_").collect();
    let project_identifier = identifiers.get(0).map_or(
        Err(::anyhow::anyhow!("URL中无法找到project_identifier")),
        |v| Ok(String::from(*v)),
    )?;
    let application_identifier = identifiers.get(1).map_or(
        Err(::anyhow::anyhow!("URL中无法找到application_identifier")),
        |v| Ok(String::from(*v)),
    )?;
    tracing::debug!(
        "获取到project:[{}],application:[{}],",
        project_identifier,
        application_identifier
    );

    //plugin identifier为url中的
    let mut file_path = String::new();

    let url = url.path().to_string();
    let mut file_path = if url.contains("?") {
        let (first, _last) =
            url.split_at(url.find("?").map_or(Err(anyhow::anyhow!("")), |v| Ok(v))?);
        String::from(&first[1..])
    } else {
        String::from(&url[1..])
    };
    if file_path == "" {
        file_path = String::from("index.html");
    }
    tracing::debug!(
        "获取到project:[{}],application:[{}],请求地址:{}",
        project_identifier,
        application_identifier,
        file_path
    );

    //组装文件路径
    let file_path = get_rrapp_file_path(&project_identifier, &application_identifier, &file_path)
        .map_err(|err| anyhow::anyhow!("获取文件路径失败:{}", err))?;

    //获取文件大小，如果太大，提示
    //app_cid 即为内容ID，为下载应用的路径中的一部分
    tracing::debug!("文件路径:{:?}", file_path);

    //获取文件内容
    let buf = read_bytes_from_pathbuf(&file_path)?;

    //获取mimetype
    let content_type = String::from(
        mime_guess::from_path(file_path)
            .first_or(mime::TEXT_PLAIN)
            .as_ref(),
    );

    http::Response::builder()
        .header("Origin", "*")
        // .mimetype(
        //     mime_guess::from_path(file_path)
        //         .first_or(mime::TEXT_PLAIN)
        //         .as_ref(),
        // )
        .header("Content-Type", content_type)
        .header("Content-Length", buf.len())
        .status(200)
        .body(buf)
        .map_err(|err| anyhow::anyhow!("{}", err))
}

pub fn get_rrapp_file_path(
    project_identifier: &String,
    application_identifier: &String,
    file_relative: &String,
) -> anyhow::Result<PathBuf> {
    //静态文件路径
    let file_path = if project_identifier != "" {
        rrg01_home_path()?
            .join(crate::constants::PROJECT_ROOT_PATH)
            .join(project_identifier.replace(":", "_"))
            .join(application_identifier.replace(":", "_"))
            .join("content")
            .join(file_relative)
    } else {
        rrg01_home_path()?
            .join(crate::constants::APP_ROOT_PATH)
            .join(application_identifier.replace(":", "_"))
            .join("content")
            .join(file_relative)
    };
    Ok(file_path)
}
